<template>
  <div ref="sv_view" class="scroll-view">
    <div ref="sv_pannel" class="view-pannel">
      <slot></slot>
    </div>
    <div class="v-react">
      <div ref="sv_vslide" class="v-slide">
        <div ref="sv_vbar" class="v-bar"></div>
      </div>
    </div>
    <div class="h-react">
      <div ref="sv_hslide" class="h-slide">
        <div ref="sv_hbar" class="h-bar"></div>
      </div>
    </div>
  </div>
</template>
<script>
import { ref, onMounted, reactive } from 'vue'
export default {
  setup() {
    const sv_view = ref()
    const sv_pannel = ref()
    const sv_hslide = ref()
    const sv_vslide = ref()
    const sv_hbar = ref()
    const sv_vbar = ref()

    let view, pannel, hslide, vslide, hbar, vbar, mx, my, bar

    const state = reactive({
      isDrag: false
    })

    onMounted(() => {
      view = sv_view.value
      pannel = sv_pannel.value
      hslide = sv_hslide.value
      vslide = sv_vslide.value
      hbar = sv_hbar.value
      vbar = sv_vbar.value

      mousedown(hbar)
      mousedown(vbar)
      mousemove()
      scroll()
    })

    function scroll() {
      view.addEventListener('mousewheel', event => {
        let dir = event.wheelDelta > 0 ? 1 : -1
        event.altKey ? scrollX(dir) : scrollY(dir)
      })
    }
    function scrollX(dir) {
      let left = pannel.offsetLeft + (50 * dir)
      let max = pannel.offsetWidth - view.offsetWidth
      left = left < -max ? -max : left
      left = left > 0 ? 0 : left
      let x = (hslide.offsetWidth - hbar.offsetWidth) * left / max
      hbar.style.left = -x + 'px'
      pannel.style.left = left + 'px'
    }

    function scrollY(dir) {
      let top = pannel.offsetTop + (50 * dir)
      let pHeight = pannel.offsetHeight
      let vHeight = view.offsetHeight
      let slideHeight = vslide.offsetHeight
      let barHeight = vbar.offsetHeight
      let max = pHeight - vHeight
      top = top < -max ? -max : top
      top = top > 0 ? 0 : top
      let y = (slideHeight - barHeight) * top / max
      vbar.style.top = -y + 'px'
      pannel.style.top = top + 'px'
    }

    function mousedown(el) {
      el.addEventListener('mousedown', (event) => {
        state.isDrag = true
        bar = event.target
        mx = event.x
        my = event.y
      })
      document.addEventListener('mouseup', event => {
        state.isDrag = false
      })
    }

    function mousemove() {
      document.addEventListener('mousemove', event => {
        if (!state.isDrag) return
        let x = event.x - mx
        let y = event.y - my
        mx = event.x
        my = event.y
        if (bar == hbar) {
          x = hbar.offsetLeft + x
          x = x < 0 ? 0 : x
          let max = hslide.offsetWidth - hbar.offsetWidth
          x = x > max ? max : x
          hbar.style.left = x + 'px'
          hMove(x)

        } else if (bar == vbar) {
          y = vbar.offsetTop + y
          y = y < 0 ? 0 : y
          let max = vslide.offsetHeight - vbar.offsetHeight
          y = y > max ? max : y
          vbar.style.top = y + 'px'

          vMove(y)
        }
      })
    }

    function vMove(y) {
      let pHeight = pannel.offsetHeight
      let vHeight = view.offsetHeight
      let slideHeight = vslide.offsetHeight
      let barHeight = vbar.offsetHeight
      let top = y * (pHeight - vHeight) / (slideHeight - barHeight)
      pannel.style.top = -top + 'px'
    }

    function hMove(x) {
      let pWidth = pannel.offsetWidth
      let vWidth = view.offsetWidth
      let slideWidth = hslide.offsetWidth
      let barWidth = hbar.offsetWidth
      let left = x * (pWidth - vWidth) / (slideWidth - barWidth)
      pannel.style.left = -left + 'px'
    }


    return {
      sv_view, sv_pannel, sv_hslide, sv_vslide, sv_hbar, sv_vbar
    }
  },
}
</script>
<style lang="less" scoped>
.scroll-view {
  overflow: hidden;
  width: 100%;
  height: 100%;
  position: relative;
  .view-pannel {
    padding: 40px;
    position: absolute;
  }
  .v-react,
  .h-react {
    position: absolute;
  }
  .v-react {
    top: 0;
    right: 0;
    width: 20px;
    height: 100%;
    background-image: linear-gradient(
      to left,
      rgba(0, 0, 0, 0.3),
      rgba(0, 0, 0, 0)
    );
  }
  .h-react {
    left: 0;
    bottom: 0;
    height: 20px;
    width: 100%;
    background-image: linear-gradient(
      to top,
      rgba(0, 0, 0, 0.3),
      rgba(0, 0, 0, 0)
    );
  }
  .v-slide,
  .h-slide {
    position: absolute;
    border-radius: 2px;
    box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.5);
    background-color: rgba(255,255,255,.3);
  }
  .v-slide {
    width: 4px;
    height: 90%;
    top: 5%;
    right: 8px;
  }
  .h-slide {
    height: 4px;
    width: 96%;
    left: 2%;
    bottom: 8px;
  }
  .v-bar,
  .h-bar {
    position: absolute;
    background-color: rgba(0, 0, 0, 0.75);
    border-radius: 8px;
    box-shadow: 0 0 4px 2px rgba(255, 255, 255, 0.5);
    cursor: pointer;
  }
  .v-bar {
    width: 16px;
    height: 40px;
    top: 0;
    left: -7px;
  }
  .h-bar {
    height: 16px;
    width: 40px;
    left: 0;
    bottom: -7px;
  }
}
</style>